#!/usr/bin/env python
# -*- coding: utf-8 -*-


import transaction
from datetime import datetime
from enum import IntEnum
# 导入ZODB相关模块
from ZODB import FileStorage, DB
from ZEO.ClientStorage import ClientStorage
from persistent.mapping import PersistentMapping
from modules.project.models import UiTestCase

class DBClient:
    """ZODB数据库客户端"""
    def __init__(
        self,
        host: str = None,
        port: int = None,
        db_file: str = None,
        timeout: int = 10000):
        """初始化数据库客户端

        Args:
            name (str): 数据库名称
            db_uri (str): 数据库连接URI
            timeout (int): 超时时间（毫秒）
        """
        # 初始化属性
        self.storage = None
        self.db = None
        self.connection = None
        self.is_open = False
        self.root = None
        
        try:
            # 创建数据库连接
            if host and port and db_file:
                raise ValueError("只能指定host和port或者db_file")
            if not host and not port and not db_file:
                raise ValueError("必须指定host和port或者db_file")
            
            if host and port:
                self.storage = ClientStorage(host, port)
            else:
                self.storage = FileStorage.FileStorage(db_file)
                
            self.db = DB(self.storage)
            self.connection = self.db.open()
            self.is_open = True
            self.root = self.connection.root()
            
            # 确保testcases容器存在
            if not hasattr(self.root, 'testcases'):
                self.root.testcases = PersistentMapping()
                transaction.commit()
        except Exception as e:
            # 发生异常时清理资源
            self.close()
            raise e

    def close(self):
        """关闭数据库连接"""
        if self.is_open:
            self.is_open = False
            try:
                self.flush()
            except:
                pass  # 忽略刷新时的错误
                
        # 安全关闭各个资源，即使它们可能未初始化
        if hasattr(self, 'connection') and self.connection is not None:
            try:
                self.connection.close()
            except:
                pass
                
        if hasattr(self, 'db') and self.db is not None:
            try:
                self.db.close()
            except:
                pass
                
        if hasattr(self, 'storage') and self.storage is not None:
            try:
                self.storage.close()
            except:
                pass


    def new_test_case(self, name: str, owner: str, type: IntEnum, description: str) -> UiTestCase:
        """创建一个新的UI测试用例"""
        test_id = self.gen_test_case_id()
        test_case = UiTestCase(test_id, name, owner, type, description)
        self.root.testcases[test_id] = test_case
        transaction.commit()
        return test_case


    def list_test_cases(self):
        """列出所有测试用例"""
        return self.root.testcases


    def flush(self):
        """将内存中的数据刷新到数据库"""
        transaction.commit()

    def gen_test_case_id(self) -> int:
        """生成唯一的测试用例ID
        
        使用更严谨的算法生成唯一ID，结合时间戳、随机数和序列号，确保在分布式环境下也能生成唯一ID。
        同时处理可能的冲突情况，并确保生成的ID格式一致且便于排序和查询。
        
        返回:
            int: 唯一的测试用例ID
        """
        # 导入UUID模块，仅在函数内部导入，避免全局依赖
        import uuid
        import random
        
        # 获取当前时间戳（毫秒级）
        timestamp = int(datetime.now().timestamp() * 1000)
        
        # 获取当前测试用例数量作为序列号基础
        sequence = len(self.root.testcases) + 1
        
        # 生成随机数（0-999）
        rand_num = random.randint(0, 999)
        
        # 生成UUID的一部分并转换为整数（取前8位十六进制，转为整数）
        uuid_part = int(str(uuid.uuid4()).replace('-', '')[:8], 16) % 10000
        
        # 组合各部分，确保唯一性
        # 格式: TTTTTTSSSSRRRRUUUU
        # T: 时间戳（取后6位）
        # S: 序列号（4位）
        # R: 随机数（4位）
        # U: UUID部分（4位）
        unique_id = (timestamp % 1000000) * 1000000000000 + sequence * 100000000 + rand_num * 10000 + uuid_part
        
        # 检查ID是否已存在，如果存在则重新生成
        while unique_id in self.root.testcases:
            # 增加随机数部分以避免冲突
            rand_num = random.randint(0, 999)
            uuid_part = int(str(uuid.uuid4()).replace('-', '')[:8], 16) % 10000
            unique_id = (timestamp % 1000000) * 1000000000000 + sequence * 100000000 + rand_num * 10000 + uuid_part
        
        return unique_id